using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.TransportProxy.Interop;

namespace Microsoft.Samples.BizTalk.Adapter.Tcp.Send
{
    /// <summary>
    ///     This class implements a transmitter batch that is used by the messaging engine
    ///     to pass messages to the send adapter to be asynchronously sent.
    /// </summary>
    /// <author>
    ///     Paul Brown
    /// </author>
    public class TransmitterBatch : IBTTransmitterBatch
    {
        #region Private Instance Members

        private SendAdapter         _adapter;           // The send adapter
        private List<SendLocation>  _sendLocations;     // The send locations containing the messages to transmit

        #endregion

        #region Constructor

        /// <summary>
        ///     This constructor initializes the instance.
        /// </summary>
        public TransmitterBatch(SendAdapter adapter)
        {
            // Validate
            if (adapter == null) throw new ArgumentNullException("adapter");

            // Initialize
            this._adapter = adapter;
            this._sendLocations = new List<SendLocation>();
        }

        #endregion

        #region Public Instance Properties

        /// <summary>
        ///     This property returns a reference to the send adapter.
        /// </summary>
        public SendAdapter SendAdapter
        {
            get { return (this._adapter); }
        }

        #endregion

        #region IBTTransmitterBatch Members

        /// <summary>
        ///     This method is called by the messaging engine.  The adapter can return the maximum number of messages
        ///     that it will accept in a batch.
        /// </summary>
        public object BeginBatch(out int maxBatchSize)
        {
            if (this.SendAdapter.TraceSwitch.TraceVerbose)
                TraceHelper.WriteEntry(TraceLevel.Verbose, ResourceConstants.SendBeginBatch, this.SendAdapter.TransmitBatchSize);

            // Return maximum batch size
            maxBatchSize = this.SendAdapter.TransmitBatchSize;

            // Return null as we do not have a DTC transaction to return
            return (null);
        }

        /// <summary>
        ///     This method clears the batch.
        /// </summary>
        public void Clear()
        {
            if (this.SendAdapter.TraceSwitch.TraceVerbose)
                TraceHelper.WriteEntry(TraceLevel.Verbose, ResourceConstants.SendClearBatch);

            // Clear array
            this._sendLocations.Clear();
        }

        /// <summary>
        ///     This method signifies that the messaging engine is handing the batch over for processing.
        /// </summary>
        public void Done(IBTDTCCommitConfirm commitConfirm)
        {
            if (this.SendAdapter.TraceSwitch.TraceVerbose)
                TraceHelper.WriteEntry(TraceLevel.Verbose, ResourceConstants.SendDoneBatch, this._sendLocations.Count);

            // Send work to the dispatcher (if we throw an error it will filter back to BizTalk)
            foreach (SendLocation sendLocation in this._sendLocations)
            {
                // If this send location supports duplex connections, send to a different worker thread
                if (sendLocation.SupportsDuplex)
                {
                    // Duplex transmission of data
                    this.SendAdapter.Dispatcher.AddWorkItem(new DuplexWorkItem(sendLocation));
                }
                else
                {
                    // Normal transmission of data
                    this.SendAdapter.Dispatcher.AddWorkItem(new TransmitWorkItem(sendLocation));
                }
            }
        }

        /// <summary>
        ///     This method transmits a message to the adapter.  It enqueues the message ready for BizTalk
        ///     to signify the end of the batch (by calling Done()) at which point it transmits the messages.
        /// </summary>
        public bool TransmitMessage(IBaseMessage msg)
        {
            if (this.SendAdapter.TraceSwitch.TraceVerbose)
                TraceHelper.WriteEntry(TraceLevel.Verbose, ResourceConstants.SendTransmitMessage, msg.MessageID);

            //// Print out context properties
            //for (int i = 0; i < msg.Context.CountProperties; i++)
            //{
            //    string name;
            //    string ns;
            //    msg.Context.ReadAt(i, out name, out ns);
            //    TraceHelper.WriteRawEntry(TraceLevel.Verbose, string.Format("{0}: {1}", name, ns));
            //}

            // Create a send location
            SendLocation sendLocation = new SendLocation(this.SendAdapter, msg);

            // Add to array
            this._sendLocations.Add(sendLocation);

            // Return false to indicate messages are transmitted asynchronously and not synchronously during Done()
            return (false);
        }

        #endregion
    }
}
